using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ProgramMain.Framework
{
    public class HistoryItem<TValue>
        where TValue : new()
    {
        public long Ticks;
        public TValue Value;

        public HistoryItem()
        {
            UpdateTicks();
            Value = new TValue();
        }

        public HistoryItem(TValue aValue)
        {
            UpdateTicks();
            Value = aValue;
        }

        public void UpdateTicks()
        {
            Ticks = DateTime.Now.Ticks;
        }
    };

    public class SerializableHistoryList<TKey, TValue>
        where TValue : new()
        where TKey : new()
    {
        public static readonly TKey EmptyKey = new TKey();
        public static readonly TValue EmptyValue = new TValue();

        private int m_MaxSize = 100;
        public int MaxSize
        {
            get { return m_MaxSize; }
            set
            {
                if (m_MaxSize != value)
                {
                    m_MaxSize = value;
                    //OnMaxSizeChanged(EventArgs.Empty);
                }
            }
        }

        private SerializableDictionary<TKey, HistoryItem<TValue> > m_Dictionary = new SerializableDictionary<TKey, HistoryItem<TValue> >();

        public string Dictionary
        {
            get
            {
                return SerializeHistory();
            }
            set
            {
                try
                {
                    DeserializeHistory(value);
                }
                catch (Exception)
                {
                    //do nothing
                }
            }
        }

        private string SerializeHistory()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(SerializableDictionary<TKey, HistoryItem<TValue> >));
            MemoryStream memoryStream = new MemoryStream();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            serializer.Serialize(xmlTextWriter, m_Dictionary);
            memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(memoryStream.ToArray());
            return constructedString;
        }

        private void DeserializeHistory(string constructedString)
        {
            if (constructedString != null && constructedString.Length > 0)
            {
                XmlSerializer serializer = new XmlSerializer(typeof(SerializableDictionary<TKey, HistoryItem<TValue> >));
                UTF8Encoding encoding = new UTF8Encoding();
                Byte[] byteArray = encoding.GetBytes(constructedString);
                MemoryStream memoryStream = new MemoryStream(byteArray);
                XmlTextReader xmlTextReader = new XmlTextReader(memoryStream);
                m_Dictionary = (SerializableDictionary<TKey, HistoryItem<TValue>>)serializer.Deserialize(xmlTextReader);
            }
        }

        private void DeleteOldHistoryItems()
        {
            if (m_Dictionary.Count > m_MaxSize)
            {
                long Ticks = Int64.MaxValue;
                TKey itemID = EmptyKey;
                bool bFound = false;
                foreach (KeyValuePair<TKey, HistoryItem<TValue>> i in m_Dictionary)
                {
                    if (i.Value.Ticks < Ticks)
                    {
                        Ticks = i.Value.Ticks;
                        itemID = i.Key;
                        bFound = true;
                    }
                }
                if (bFound)
                {
                    m_Dictionary.Remove(itemID);
                }
            }
        }

        protected void StoreToHistory(TKey itemID, TValue Value)
        {
            if (!m_Dictionary.ContainsKey(itemID))
            {
                m_Dictionary.Add(itemID, new HistoryItem<TValue>(Value));
                DeleteOldHistoryItems();
            }
            else
            {
                m_Dictionary[itemID].Value = Value;
                m_Dictionary[itemID].UpdateTicks();
            }
        }

        protected TValue ReadFromHistory(TKey itemID)
        {
            if (m_Dictionary.ContainsKey(itemID))
                return m_Dictionary[itemID].Value;
            else
                return EmptyValue;
        }
    }
}
